package com.rockville.testing;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;

import org.apache.log4j.Logger;

import com.rockville.httpRequest.HttpRequestUrl;
import com.rockville.ufone.DBProc;
import com.sun.syndication.feed.WireFeed;
import com.sun.syndication.feed.synd.SyndContentImpl;
import com.sun.syndication.feed.synd.SyndEnclosureImpl;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.feed.synd.SyndFeedImpl;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;

/**
 * @author Asad
 * @modified Qaiser Suleman
 */
public class CricketNewsParser implements Runnable {
	
    private static final Logger log = Logger.getLogger(CricketNewsParser.class);
    private static final String newsImgBasePath = "/data/portal/portal_images/rss/";    
    private String feedUrl = null;
    private String feedName = null;
    private String feedId = null;    
    
    public CricketNewsParser(String id, String name, String url) {
    	feedId = id;
    	feedName = name;
        feedUrl = url;
    }
    
    /**
     * <pre>
     * This function is used to fetch data for a web URL
     * </pre>
     * @param feed_URL
     * @param feed_UserName
     * @param feed_Password
     * @param feed_Heading
     */
    public void loadChannelData() {		
		String strTitle = "", strDescp = "", strImage = "";
		Date newsDate = null;
		Date channelUpdateDate = null;
		URL feed = null;
		try {
			feed = new URL(feedUrl);
		} catch (MalformedURLException ex) {
			log.error("MalformedURLException creating feed URL: " + feedUrl, ex);
		} catch (Exception ex) {
			log.error("Exception creating feed URL: " + feedUrl, ex);
		}

		try {
			DBProc db = DBProc.getInstance();
			SyndFeedInput input = new SyndFeedInput();
			SyndFeed synfeed = input.build(new XmlReader(feed));

			WireFeed wf = synfeed.createWireFeed();
			SyndFeedImpl sfi = new SyndFeedImpl(wf);
			SyndEntryImpl sei = new SyndEntryImpl();
			// sdformatter = new SimpleDateFormat("EEE MMM dd, yyyy HH:mm:ss");
			SyndContentImpl sci = null;
//			log.debug("sfi Title" + sfi.getTitle());
//			log.debug("sfi Title" + sfi.getDescription());
			Date channelPubDate = sfi.getPublishedDate();
			if(channelPubDate != null) {
				log.debug("("+feedId+") channel's publishedDate " + channelPubDate);
			}
			List lstFeed = synfeed.getEntries();			
			ListIterator it = lstFeed.listIterator();
			Date lastNewsDate = new Date();
			if(it.hasNext()) {
				lastNewsDate = db.getChannelLastUpdateDate(feedId);
			}			
			Collections.sort(lstFeed, new SyndEntryComparator());
			int counter = 0;
			while (it.hasNext()) {
				sei = (SyndEntryImpl) it.next();
				sci = (SyndContentImpl) sei.getDescription();
				strTitle = sei.getTitle();
				strDescp = sci.getValue();
				newsDate = sei.getPublishedDate();
				List enc = sei.getEnclosures();
				if(enc.size() > 0) {
					SyndEnclosureImpl encl = (SyndEnclosureImpl)enc.get(0);
					if(encl.getType().indexOf("image") != -1) {
						String imgUrl = encl.getUrl();
						strImage = HttpRequestUrl.downloadImage(imgUrl, newsImgBasePath);
					}
				}
				
				if(newsDate == null) {
					newsDate = (channelPubDate != null ? channelPubDate : new Date(System.currentTimeMillis()-(counter*1000)));
				}
				if (lastNewsDate == null || newsDate == null || lastNewsDate.compareTo(newsDate) < 0) {
					log.debug("(" + feedId+ ") New News Item Found, lastNewsDate:" + lastNewsDate + ", newsDate:" + newsDate);					
					log.debug("("+feedId+") Title: " + strTitle);					
					log.debug("("+feedId+") Description: " + strDescp);
					db.saveNews(strTitle, strDescp, newsDate, feedId, strImage);
					counter++;
				}
//				else {
//					log.debug("(" + feedId+ ") is already updated. lastNewsDate:" + lastNewsDate + ", newsDate:" + newsDate);
//				}
                if(channelUpdateDate == null)
                	channelUpdateDate = newsDate;
                else if(channelUpdateDate.compareTo(newsDate) < 0)
                	channelUpdateDate = newsDate;
				
			}// end while
			db.updateChannelLastNewsDate(feedId, channelUpdateDate);
			log.debug("("+feedId+") Latest News items found " + counter + " out of "+lstFeed.size());
			
		} catch (NullPointerException npex) {
			log.error("("+feedId+") NullPointerException parsing URL: " + feedUrl, npex);
		} catch (IOException ex) {
			log.error("("+feedId+") IOException parsing URL: " + feedUrl, ex);
		} catch (Exception ex) {
			log.error("("+feedId+") Exception parsing URL: " + feedUrl, ex);
		}
    }
    
    static class SyndEntryComparator implements Comparator {
        public int compare(Object o1, Object o2) {
          if (!(o1 instanceof SyndEntryImpl) || !(o2 instanceof SyndEntryImpl)) throw new ClassCastException();

          Date d1 = ((SyndEntryImpl) o1).getPublishedDate();
          Date d2 = ((SyndEntryImpl) o2).getPublishedDate();
          if(d1 != null && d2 != null)
        	  return d1.compareTo(d2);
          else
        	  return 0;
        }
      }    
    /**
     * return data within the body tag.
     * @param html
     * @return
     */
    private static String removeUnwantedHtmlTags(String html) {
        html = html.replaceAll("\n", "");
        if( html.contains("<body>") ) {
            html = html.substring( html.indexOf("<body>")+6, html.lastIndexOf("</body>") );
        }
        
        return html.trim().replaceAll("  ", " ");
    }
    
    /**
     * <pre>
     * Direct Parsing without using any dom api.
     * Gives the DateTime from the rss content passed.
     * </pre>
     * @param fileContents
     * @return
     */
    private String getDateAndTimeFromXml(String fileContents) {
        String date_time;
        
        date_time = getTaggedDataFromXml(fileContents, "DateAndTime");
        
        return parseReutersDate(date_time);
    }
    
    private static String parseReutersDate(String rawDate) {
        String parsed_Date = "";
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
        Date dt;
        
        try {
            dt = formatter.parse(rawDate);
            formatter.applyPattern("EEE MMM dd, yyyy HH:mm:ss");
            parsed_Date = formatter.format(dt);
        }
        catch(Exception ex) {
            log.error("parseReutersDate rawDate="+rawDate, ex);
            parsed_Date = "DateTime unavailable";
        }        
        return parsed_Date;
    }
    
    /**
     * <pre>
     * Direct parsing without using any dom api.
     * Get the content of <i>tag</i> 
     * from <i>fileContents</i> 
     * </pre>
     * @param fileContents
     * @param tag
     * @return
     */
    private String getTaggedDataFromXml(String fileContents, String tag) {
        String xmlTaggedData = "";
        int begIndex = 0;
        int endIndex = 0;
        String startTag = "<"+tag+">";
        String endTag = "</"+tag+">";
        
        try {
            begIndex = fileContents.indexOf(startTag);
            if(begIndex > -1) {
                fileContents = fileContents.substring(begIndex);

                begIndex = fileContents.indexOf(">")+1;
                if(begIndex > -1)
                    fileContents = fileContents.substring(begIndex);

                endIndex = fileContents.indexOf(endTag);

                xmlTaggedData = fileContents.substring( 0, endIndex);
            }
        }
        catch(Exception ex) {
            log.error("getTaggedDataFromXml() tag="+tag, ex);
        }        
        return xmlTaggedData;
    }
    
    /**
     * <pre>
     * Direct parsing without using any dom api.
     * Gets the Text in the passed rss content.
     * </pre>
     * @param fileContents
     * @return
     */
    private String getTextFromNewsMlXml(final String fileContents){
        String strText_rss = "";
        String strText = "";
        strText = fileContents;
        
        int intIndex_DataContent=-1;
        intIndex_DataContent=strText.toUpperCase().indexOf("<DataContent>".toUpperCase());
        int intIndex_BodyTagStart=-1;
        if(intIndex_DataContent>-1)
            intIndex_BodyTagStart = strText.toUpperCase().indexOf("<body>".toUpperCase(),intIndex_DataContent);
        int intIndex_BodyTagEnd=-1;
        if(intIndex_BodyTagStart>-1)
            intIndex_BodyTagEnd = strText.toUpperCase().indexOf("</body>".toUpperCase(),intIndex_BodyTagStart);
        
        try {
            strText_rss=strText.substring(intIndex_BodyTagStart,intIndex_BodyTagEnd);
        }
        catch(Exception exSubstring){}
        
        strText_rss=strText_rss.replaceAll("</?body>", "");
        //log.debug("strText_rss: "+strText_rss);
        return strText_rss.trim();
                
    }
    
    /**
     * <pre>
     * Direct Parsing without using any dom api.
     * Gives the Image name from the rss content passed.
     * </pre>
     * @param fileContents
     * @return
     */
    private String getImageFromNewsMlXml(String fileContents) {
        String imageName = "";
        int begIndex = 0;
        int endIndex = 0;
        
        try {
            begIndex = fileContents.indexOf("Image Wrapper");
            if(begIndex > -1) {
                fileContents = fileContents.substring(begIndex);

                begIndex = fileContents.indexOf("Href=")+5;
                if(begIndex > -1)
                    fileContents = fileContents.substring(begIndex);

                begIndex = fileContents.indexOf("\"")+1;
                if(begIndex > -1)
                    fileContents = fileContents.substring(begIndex);

                endIndex = fileContents.indexOf("\"");

                imageName = fileContents.substring( 0, endIndex);
            }
        }
        catch(Exception ex) {
            log.error("getImageFromNewsMlXml(): ", ex);
        }        
        return imageName;
    }
    
    /**
     * <pre>
     * Direct Parsing without using any dom api.
     * Gets the Heading from the rss content passed.
     * </pre>
     * @param fileContents
     * @return
     */
    private String getHeadingFromXml (String fileContents) {
        String xmlHeading = "";
        int begIndex = 0;
        int endIndex = 0;
        
        try {
            begIndex = fileContents.indexOf("<HeadLine>");
            if(begIndex > -1) {
                fileContents = fileContents.substring(begIndex);

                begIndex = fileContents.indexOf(">")+1;
                if(begIndex > -1)
                    fileContents = fileContents.substring(begIndex);

                endIndex = fileContents.indexOf("</HeadLine>");

                xmlHeading = fileContents.substring( 0, endIndex);
            }
        }
        catch(Exception ex) {
            log.error("getHeadingFromXml(): ", ex);
        }        
        return xmlHeading;
    }
    
    /**
     * <pre>This Function returns the build date of the URL[ULRStr],
     * which is suppose to be an XML Feed.
     * The Function employee basic authentication to get the response.</pre>
     * @param ULRStr
     * @param userName
     * @param password
     * @return Date
     */
    public Date getLastBuildDate(String ULRStr, String userName, String password) {

        Date dtLastBuild = null;
        String URLResult = "";
        
        java.net.HttpURLConnection connection = null;
        BufferedReader in = null;
            
        try {
            java.net.URL url = new java.net.URL(ULRStr);
            java.net.HttpURLConnection.setFollowRedirects(true);
            connection = (java.net.HttpURLConnection) url.openConnection();            
            connection.setRequestMethod("GET");
            connection.setRequestProperty("User-Agent","Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)");
            connection.setRequestProperty("Content-Length", "0");
            connection.setRequestProperty("Connection", "close");
            connection.setDoOutput(true);
            connection.setDoInput(true);
            
            connection.setAllowUserInteraction(true);
            connection.setDefaultUseCaches(false);
            
            //Base64 b64 = new Base64();
            String userPass;
            userPass = userName + ":" + password;
            userPass=com.rockville.httpRequest.Base64Coder.encodeString(userPass);
            connection.setRequestProperty("Authorization", "Basic " + userPass);
            
            int intResponseCode = connection.getResponseCode();
            //log.debug("" + intResponseCode + " : " + strUrl + " in HttpRequestUrl(" + strUrl + ","+strUserName+","+strPassword+") in "+this.getClass().getName());
            if (intResponseCode != HttpURLConnection.HTTP_OK) {
                log.warn("Response code from ( " + ULRStr + " ) is not HTTP_OK, returning!");
                return null;
            }
            
            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                URLResult += inputLine;
                if (URLResult.matches("(?i).*</lastBuildDate>.*")) {
                    break;
                }
            }

            // Extracting a substring from a string
            String sBuildDate = URLResult.substring(URLResult.indexOf("<lastBuildDate>") + 15, URLResult.indexOf("</lastBuildDate>"));
            SimpleDateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
            dtLastBuild = formatter.parse(sBuildDate);
            
            log.debug("last build date found [" + dtLastBuild.toString() + "] for channel [" + ULRStr + "]");
        } catch (Exception exc) {
            log.error("getLastBuildDate ULRStr="+ULRStr+", userName="+userName+", password="+password, exc);
        }
        finally {
            try {
                if (in != null) {
                    in.close();
                }                
            } catch (Exception exBufferedReaderClose) {            	
            }
            in = null;
            try {
                if (connection != null) {
                    connection.disconnect();
                }
            } catch (Exception exUrlConnectionClose) {         
            }
            connection = null;
        }        
        return dtLastBuild;
    }

	@Override
	public void run() {		
		log.info("("+feedId+") Task for feed: "+feedName+" - "+feedUrl+" STARTED");
		loadChannelData();
		log.info("("+feedId+") Task for feed: "+feedName+" - "+feedUrl+" FINISHED -------------");
	}    
    
    public static void main(String args[]){
        CricketNewsParser rsdbean = new CricketNewsParser("52", "cricket news", "http://www.skysports.com/rss/0,20514,12123,00.xml");
        rsdbean.loadChannelData();
    }
    
}